package pos.Driving.Train;


import javax.media.j3d.*;
import javax.vecmath.*;
import javax.xml.xpath.XPath;
import javax.xml.xpath.XPathFactory;
import org.w3c.dom.Document;
import pos.Driving.Path.PosPoint;
import pos.utils.*;

/**
 *
 * @author plus
 */
public class Carriage extends TransformGroup implements Invokeable{

    private Train MyTrain;
    private Group VisualCarriage;
    private double offsetD;
    private Bogie[] Bogies;
    private Door [] DoorsLeft, DoorsRight;
    private Pantograph MyPant;
    
    PosPoint currentPos=new PosPoint();
    
    public Carriage(Train MyTrain, Document doc, int id,
            Door [] DoorsLeft,Door [] DoorsRight)throws Exception {
        XPathFactory xpfactory = XPathFactory.newInstance();
        XPath xpath = xpfactory.newXPath();
        this.MyTrain = MyTrain;
        this.offsetD = 
                Double.parseDouble(xpath.evaluate(getXPathBase(id,"offset"), doc).trim());
        VisualCarriage
                = ObjectFactory.createObject(
                xpath.evaluate(getXPathBase(id,"carriageModelKey"), doc));
        defColorMaterialSet(VisualCarriage);
        Transform3D trans = new Transform3D();
        trans.set(new Vector3d(offsetD, 0d, 0d));
        this.setTransform(trans);
        this.setCapability(this.ALLOW_TRANSFORM_WRITE);
        this.addChild(VisualCarriage);
        MyTrain.getTrainGroup().addChild(this);
        Point2d BogiesOffsetD = new Point2d(
                Double.parseDouble(xpath.evaluate(getXPathBase(id,"bogieOffset[1]"), doc)),
                Double.parseDouble(xpath.evaluate(getXPathBase(id,"bogieOffset[2]"), doc))
        );
        initBogie(BogiesOffsetD,
                xpath.evaluate(getXPathBase(id,"bogieModelKey"), doc));
        this.DoorsLeft=DoorsLeft;
        this.DoorsRight=DoorsRight;
        for (Door door :this.DoorsLeft)
            addChild(door);
        for (Door door :this.DoorsRight)
            addChild(door);
    }
    @SuppressWarnings("static-access")
    public Carriage(Train MyTrain, double offsetD, Point2d BogiesOffsetD, 
            String ModelFileKey,String BogiesFileKey, 
            Door [] DoorsLeft,Door [] DoorsRight) {
        this.MyTrain = MyTrain;
        this.offsetD = offsetD;
        //this.Bogies = Bogies;
        VisualCarriage = ObjectFactory.createObject(ModelFileKey);
        defColorMaterialSet(VisualCarriage);
        Transform3D trans = new Transform3D();
        trans.set(new Vector3d(offsetD, 0d, 0d));
        this.setTransform(trans);
        this.setCapability(this.ALLOW_TRANSFORM_WRITE);
        this.addChild(VisualCarriage);
        MyTrain.getTrainGroup().addChild(this);
        initBogie(BogiesOffsetD,BogiesFileKey);
        this.DoorsLeft=DoorsLeft;
        this.DoorsRight=DoorsRight;
        for (Door door :this.DoorsLeft)
            addChild(door);
        for (Door door :this.DoorsRight)
            addChild(door);
//        RefreshPosition();
    }
    
    private void initBogie(Point2d BogiesOffsetD,String BogiesFileKey){
        Bogies=new Bogie[]{new Bogie(MyTrain,offsetD+BogiesOffsetD.x,BogiesFileKey),
                           new Bogie(MyTrain,offsetD+BogiesOffsetD.y,BogiesFileKey)};
    }
    
    public PosPoint RefreshPosition(){
        currentPos.d=MyTrain.getTrainPos().d+offsetD;
        //currentPos=MyTrain.MyRail.makePath(currentPos);
        PosPoint posBogieA, posBogieB;
        posBogieA=Bogies[0].RefreshPosition();
        posBogieB=Bogies[1].RefreshPosition();
        currentPos.AngH=0.5*(posBogieA.AngH+posBogieB.AngH);
        
        double deltaZ=posBogieB.pos.z-posBogieA.pos.z,
                deltaY=posBogieB.pos.y-posBogieA.pos.y,
                deltaX=posBogieB.pos.x-posBogieA.pos.x,
                deltaD=Bogies[1].offsetD-Bogies[0].offsetD,
                step=(Bogies[1].offsetD-offsetD)/deltaD;
        currentPos.pos=new Point3d(posBogieB.pos.x-deltaX*step,
                posBogieB.pos.y-deltaY*step,
                posBogieB.pos.z-deltaZ*step);
        //currentPos.AngV=0.5*(posBogieA.AngV+posBogieB.AngV);
        if (Math.abs(deltaX)<0.01){
            if (deltaZ>0)
                currentPos.AngV=-Math.PI/2;
            else
                currentPos.AngV= Math.PI/2;
        }else
            currentPos.AngV=Math.atan2(-deltaZ,deltaX);
        
        double zfix=Math.atan2(deltaY, deltaD);
        setCarriageTransform(currentPos,zfix);
        
        return currentPos;
    }
    
    private void setCarriageTransform(PosPoint p,double Zfix){
        Transform3D transH=new Transform3D();
        transH.rotX(p.AngH);
        Transform3D transV=new Transform3D();
        transV.rotY(p.AngV);
        Transform3D transZ=new Transform3D();
        transZ.rotZ(Zfix);
        Transform3D transT=new Transform3D();
        transT.set(new Vector3d(p.pos.x,p.pos.y,p.pos.z));
        
        transT.mul(transV);
        transT.mul(transZ);
        transT.mul(transH);
        
        this.setTransform(transT);
    }
    
    public void openDoor(boolean isRightDoor){
        if (isRightDoor){
            for(Door door:DoorsRight){
                door.open();
            }
        }else{
            for(Door door:DoorsLeft){
                door.open();
            }
        }
    }
    public void closeDoor(boolean isRightDoor){
        if (isRightDoor){
            for(Door door:DoorsRight){
                door.close();
            }
        }else{
            for(Door door:DoorsLeft){
                door.close();
            }
        }
    }
    public void syncPathID(){
        for(Bogie bogie: Bogies){
            bogie.setCurrentPath(MyTrain.getTrainPos().path_ID);
        }
    }
    @Override
    public void invoke(double Step) {
        for (Door door :this.DoorsLeft)
            door.invoke(Step);
        for (Door door :this.DoorsRight)
            door.invoke(Step);
    }
    
    private void defColorMaterialSet(Group gpLight) {
        for (int i = 0; i < gpLight.numChildren(); i++) {
            Node n = gpLight.getChild(i);
            if (n instanceof Group)
                defColorMaterialSet((Group)n);
            if (n instanceof Shape3D) {
                Shape3D shape = (Shape3D) n;
                Appearance app = shape.getAppearance();
                Material mat = app.getMaterial();
                if (shape.getName().startsWith(
                        MyTrain.MyDesc.DefColorMaterialName)){
                    mat.setAmbientColor(MyTrain.MyDesc.DefColor);
                    mat.setDiffuseColor(MyTrain.MyDesc.DefColor);
                   // System.err.println(shape.getName());
                }
            }
        }
    }
    private String getXPathBase(int id, String target){
        return "/train/carriages/carriage["+id+"]/"+target;
    }
}
